//! Built-in plugins
//! 
//! This module contains built-in plugins that provide core functionality
//! without requiring external WebAssembly modules.

pub mod http;
pub mod database;
pub mod utils;
pub mod validation;

use crate::error::Result;
use crate::models::{Value, ValueMap};
use std::collections::HashMap;

/// Built-in plugin enum to avoid dyn compatibility issues
#[derive(Debug)]
pub enum BuiltinPluginType {
    Http(http::HttpPlugin),
    Database(database::DatabasePlugin),
    Utils(utils::UtilsPlugin),
    Validation(validation::ValidationPlugin),
}

impl BuiltinPluginType {
    /// Get plugin name
    pub fn name(&self) -> &str {
        match self {
            BuiltinPluginType::Http(p) => p.name(),
            BuiltinPluginType::Database(p) => p.name(),
            BuiltinPluginType::Utils(p) => p.name(),
            BuiltinPluginType::Validation(p) => p.name(),
        }
    }

    /// Get plugin version
    pub fn version(&self) -> &str {
        match self {
            BuiltinPluginType::Http(p) => p.version(),
            BuiltinPluginType::Database(p) => p.version(),
            BuiltinPluginType::Utils(p) => p.version(),
            BuiltinPluginType::Validation(p) => p.version(),
        }
    }

    /// Get available functions
    pub fn functions(&self) -> Vec<String> {
        match self {
            BuiltinPluginType::Http(p) => p.functions(),
            BuiltinPluginType::Database(p) => p.functions(),
            BuiltinPluginType::Utils(p) => p.functions(),
            BuiltinPluginType::Validation(p) => p.functions(),
        }
    }

    /// Call a function
    pub async fn call_function(&self, function_name: &str, args: &[Value]) -> Result<Value> {
        match self {
            BuiltinPluginType::Http(p) => p.call_function(function_name, args).await,
            BuiltinPluginType::Database(p) => p.call_function(function_name, args).await,
            BuiltinPluginType::Utils(p) => p.call_function(function_name, args).await,
            BuiltinPluginType::Validation(p) => p.call_function(function_name, args).await,
        }
    }

    /// Initialize the plugin
    pub async fn initialize(&mut self, config: ValueMap) -> Result<()> {
        match self {
            BuiltinPluginType::Http(p) => p.initialize(config).await,
            BuiltinPluginType::Database(p) => p.initialize(config).await,
            BuiltinPluginType::Utils(p) => p.initialize(config).await,
            BuiltinPluginType::Validation(p) => p.initialize(config).await,
        }
    }

    /// Cleanup the plugin
    pub async fn cleanup(&mut self) -> Result<()> {
        match self {
            BuiltinPluginType::Http(p) => p.cleanup().await,
            BuiltinPluginType::Database(p) => p.cleanup().await,
            BuiltinPluginType::Utils(p) => p.cleanup().await,
            BuiltinPluginType::Validation(p) => p.cleanup().await,
        }
    }
}

/// Built-in plugin trait
pub trait BuiltinPlugin: Send + Sync {
    /// Get plugin name
    fn name(&self) -> &str;

    /// Get plugin version
    fn version(&self) -> &str;

    /// Get available functions
    fn functions(&self) -> Vec<String>;

    /// Call a function
    async fn call_function(&self, function_name: &str, args: &[Value]) -> Result<Value>;

    /// Initialize the plugin
    async fn initialize(&mut self, config: ValueMap) -> Result<()> {
        Ok(())
    }

    /// Cleanup the plugin
    async fn cleanup(&mut self) -> Result<()> {
        Ok(())
    }
}

/// Built-in plugin manager
#[derive(Debug)]
pub struct BuiltinPluginManager {
    /// Registered plugins
    plugins: HashMap<String, BuiltinPluginType>,
}

impl BuiltinPluginManager {
    /// Create a new built-in plugin manager
    pub fn new() -> Self {
        let mut manager = Self {
            plugins: HashMap::new(),
        };
        
        // Register built-in plugins
        manager.register_default_plugins();
        manager
    }
    
    /// Register default built-in plugins
    fn register_default_plugins(&mut self) {
        // Register HTTP plugin
        let http_plugin = BuiltinPluginType::Http(http::HttpPlugin::new());
        self.plugins.insert(http_plugin.name().to_string(), http_plugin);

        // Register database plugin
        let db_plugin = BuiltinPluginType::Database(database::DatabasePlugin::new());
        self.plugins.insert(db_plugin.name().to_string(), db_plugin);

        // Register utils plugin
        let utils_plugin = BuiltinPluginType::Utils(utils::UtilsPlugin::new());
        self.plugins.insert(utils_plugin.name().to_string(), utils_plugin);

        // Register validation plugin
        let validation_plugin = BuiltinPluginType::Validation(validation::ValidationPlugin::new());
        self.plugins.insert(validation_plugin.name().to_string(), validation_plugin);
    }
    
    /// Register a plugin
    pub fn register_plugin(&mut self, plugin: BuiltinPluginType) {
        let name = plugin.name().to_string();
        self.plugins.insert(name, plugin);
    }

    /// Get a plugin by name
    pub fn get_plugin(&self, name: &str) -> Option<&BuiltinPluginType> {
        self.plugins.get(name)
    }

    /// Get a mutable plugin by name
    pub fn get_plugin_mut(&mut self, name: &str) -> Option<&mut BuiltinPluginType> {
        self.plugins.get_mut(name)
    }
    
    /// Call a function on a plugin
    pub async fn call_function(
        &self,
        plugin_name: &str,
        function_name: &str,
        args: &[Value],
    ) -> Result<Value> {
        let plugin = self.get_plugin(plugin_name)
            .ok_or_else(|| crate::error::Error::Plugin(
                crate::error::PluginError::NotFound {
                    plugin_name: plugin_name.to_string(),
                }
            ))?;

        plugin.call_function(function_name, args).await
    }
    
    /// List all registered plugins
    pub fn list_plugins(&self) -> Vec<&str> {
        self.plugins.keys().map(|s| s.as_str()).collect()
    }
    
    /// Get plugin count
    pub fn plugin_count(&self) -> usize {
        self.plugins.len()
    }
    
    /// Initialize all plugins
    pub async fn initialize_all(&mut self, global_config: ValueMap) -> Result<()> {
        for (name, plugin) in &mut self.plugins {
            tracing::info!("Initializing built-in plugin: {}", name);
            
            // Extract plugin-specific config
            let plugin_config = global_config.get(name)
                .and_then(|v| v.as_object())
                .map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.clone())).collect())
                .unwrap_or_default();
            
            plugin.initialize(plugin_config).await?;
        }
        
        Ok(())
    }
    
    /// Cleanup all plugins
    pub async fn cleanup_all(&mut self) -> Result<()> {
        for (name, plugin) in &mut self.plugins {
            tracing::info!("Cleaning up built-in plugin: {}", name);
            plugin.cleanup().await?;
        }
        
        Ok(())
    }
}

impl Default for BuiltinPluginManager {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[tokio::test]
    async fn test_builtin_plugin_manager() {
        let manager = BuiltinPluginManager::new();
        
        // Should have default plugins registered
        assert!(manager.plugin_count() > 0);
        
        // Should have HTTP plugin
        assert!(manager.get_plugin("http").is_some());
        
        // Should have database plugin
        assert!(manager.get_plugin("database").is_some());
        
        // Should have utils plugin
        assert!(manager.get_plugin("utils").is_some());
        
        // Should have validation plugin
        assert!(manager.get_plugin("validation").is_some());
    }

    #[tokio::test]
    async fn test_plugin_listing() {
        let manager = BuiltinPluginManager::new();
        let plugins = manager.list_plugins();
        
        assert!(plugins.contains(&"http"));
        assert!(plugins.contains(&"database"));
        assert!(plugins.contains(&"utils"));
        assert!(plugins.contains(&"validation"));
    }
}
